 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.dialogs;

 import java.util.Arrays ;
 import java.util.List ;

 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.wizard.WizardPage;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Group;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;

 /**
  * The common superclass for wizard import and export pages.
  * <p>
  * This class is not intended to be subclassed outside of the workbench.
  * </p>
  */
 public abstract class WizardDataTransferPage extends WizardPage implements
         Listener, IOverwriteQuery {

     // constants
 protected static final int SIZING_TEXT_FIELD_WIDTH = 250;

     protected static final int COMBO_HISTORY_LENGTH = 5;

     /**
      * Creates a new wizard page.
      *
      * @param pageName the name of the page
      */
     protected WizardDataTransferPage(String pageName) {
         super(pageName);
     }

     /**
      * Adds an entry to a history, while taking care of duplicate history items
      * and excessively long histories. The assumption is made that all histories
      * should be of length <code>WizardDataTransferPage.COMBO_HISTORY_LENGTH</code>.
      *
      * @param history the current history
      * @param newEntry the entry to add to the history
      */
     protected String [] addToHistory(String [] history, String newEntry) {
         java.util.ArrayList l = new java.util.ArrayList (Arrays.asList(history));
         addToHistory(l, newEntry);
         String [] r = new String [l.size()];
         l.toArray(r);
         return r;
     }

     /**
      * Adds an entry to a history, while taking care of duplicate history items
      * and excessively long histories. The assumption is made that all histories
      * should be of length <code>WizardDataTransferPage.COMBO_HISTORY_LENGTH</code>.
      *
      * @param history the current history
      * @param newEntry the entry to add to the history
      */
     protected void addToHistory(List history, String newEntry) {
         history.remove(newEntry);
         history.add(0, newEntry);

         // since only one new item was added, we can be over the limit
 // by at most one item
 if (history.size() > COMBO_HISTORY_LENGTH) {
             history.remove(COMBO_HISTORY_LENGTH);
         }
     }

     /**
      * Return whether the user is allowed to enter a new container name or just
      * choose from existing ones.
      * <p>
      * Subclasses must implement this method.
      * </p>
      *
      * @return <code>true</code> if new ones are okay, and <code>false</code>
      * if only existing ones are allowed
      */
     protected abstract boolean allowNewContainerName();

     /**
      * Creates a new label with a bold font.
      *
      * @param parent the parent control
      * @param text the label text
      * @return the new label control
      */
     protected Label createBoldLabel(Composite parent, String text) {
         Label label = new Label(parent, SWT.NONE);
         label.setFont(JFaceResources.getBannerFont());
         label.setText(text);
         GridData data = new GridData();
         data.verticalAlignment = GridData.FILL;
         data.horizontalAlignment = GridData.FILL;
         label.setLayoutData(data);
         return label;
     }

     /**
      * Creates the import/export options group controls.
      * <p>
      * The <code>WizardDataTransferPage</code> implementation of this method does
      * nothing. Subclasses wishing to define such components should reimplement
      * this hook method.
      * </p>
      *
      * @param optionsGroup the parent control
      */
     protected void createOptionsGroupButtons(Group optionsGroup) {
     }

     /**
      * Creates a new label with a bold font.
      *
      * @param parent the parent control
      * @param text the label text
      * @return the new label control
      */
     protected Label createPlainLabel(Composite parent, String text) {
         Label label = new Label(parent, SWT.NONE);
         label.setText(text);
         label.setFont(parent.getFont());
         GridData data = new GridData();
         data.verticalAlignment = GridData.FILL;
         data.horizontalAlignment = GridData.FILL;
         label.setLayoutData(data);
         return label;
     }

     /**
      * Creates a horizontal spacer line that fills the width of its container.
      *
      * @param parent the parent control
      */
     protected void createSpacer(Composite parent) {
         Label spacer = new Label(parent, SWT.NONE);
         GridData data = new GridData();
         data.horizontalAlignment = GridData.FILL;
         data.verticalAlignment = GridData.BEGINNING;
         spacer.setLayoutData(data);
     }

     /**
      * Returns whether this page is complete. This determination is made based upon
      * the current contents of this page's controls. Subclasses wishing to include
      * their controls in this determination should override the hook methods
      * <code>validateSourceGroup</code> and/or <code>validateOptionsGroup</code>.
      *
      * @return <code>true</code> if this page is complete, and <code>false</code> if
      * incomplete
      * @see #validateSourceGroup
      * @see #validateOptionsGroup
      */
     protected boolean determinePageCompletion() {
         boolean complete = validateSourceGroup() && validateDestinationGroup()
                 && validateOptionsGroup();

         // Avoid draw flicker by not clearing the error
 // message unless all is valid.
 if (complete) {
             setErrorMessage(null);
         }

         return complete;
     }

     /**
      * Get a path from the supplied text widget.
      * @return org.eclipse.core.runtime.IPath
      */
     protected IPath getPathFromText(Text textField) {
         String text = textField.getText();
         //Do not make an empty path absolute so as not to confuse with the root
 if (text.length() == 0) {
             return new Path(text);
         }
        
         return (new Path(text)).makeAbsolute();
     }

     /**
      * Queries the user to supply a container resource.
      *
      * @return the path to an existing or new container, or <code>null</code> if the
      * user cancelled the dialog
      */
     protected IPath queryForContainer(IContainer initialSelection, String msg) {
         return queryForContainer(initialSelection, msg, null);
     }

     /**
      * Queries the user to supply a container resource.
      *
      * @return the path to an existing or new container, or <code>null</code> if the
      * user cancelled the dialog
      */
     protected IPath queryForContainer(IContainer initialSelection, String msg,
             String title) {
         ContainerSelectionDialog dialog = new ContainerSelectionDialog(
                 getControl().getShell(), initialSelection,
                 allowNewContainerName(), msg);
         if (title != null) {
             dialog.setTitle(title);
         }
         dialog.showClosedProjects(false);
         dialog.open();
         Object [] result = dialog.getResult();
         if (result != null && result.length == 1) {
             return (IPath) result[0];
         }
         return null;
     }

     /**
      * The <code>WizardDataTransfer</code> implementation of this
      * <code>IOverwriteQuery</code> method asks the user whether the existing
      * resource at the given path should be overwritten.
      *
      * @param pathString
      * @return the user's reply: one of <code>"YES"</code>, <code>"NO"</code>, <code>"ALL"</code>,
      * or <code>"CANCEL"</code>
      */
     public String queryOverwrite(String pathString) {

         Path path = new Path(pathString);

         String messageString;
         //Break the message up if there is a file name and a directory
 //and there are at least 2 segments.
 if (path.getFileExtension() == null || path.segmentCount() < 2) {
             messageString = NLS.bind(IDEWorkbenchMessages.WizardDataTransfer_existsQuestion, pathString);
         } else {
             messageString = NLS.bind(IDEWorkbenchMessages.WizardDataTransfer_overwriteNameAndPathQuestion, path.lastSegment(),
             path.removeLastSegments(1).toOSString());
         }

         final MessageDialog dialog = new MessageDialog(getContainer()
                 .getShell(), IDEWorkbenchMessages.Question,
                 null, messageString, MessageDialog.QUESTION, new String [] {
                         IDialogConstants.YES_LABEL,
                         IDialogConstants.YES_TO_ALL_LABEL,
                         IDialogConstants.NO_LABEL,
                         IDialogConstants.NO_TO_ALL_LABEL,
                         IDialogConstants.CANCEL_LABEL }, 0);
         String [] response = new String [] { YES, ALL, NO, NO_ALL, CANCEL };
         //run in syncExec because callback is from an operation,
 //which is probably not running in the UI thread.
 getControl().getDisplay().syncExec(new Runnable () {
             public void run() {
                 dialog.open();
             }
         });
         return dialog.getReturnCode() < 0 ? CANCEL : response[dialog
                 .getReturnCode()];
     }

     /**
      * Displays a Yes/No question to the user with the specified message and returns
      * the user's response.
      *
      * @param message the question to ask
      * @return <code>true</code> for Yes, and <code>false</code> for No
      */
     protected boolean queryYesNoQuestion(String message) {
         MessageDialog dialog = new MessageDialog(getContainer().getShell(),
                 IDEWorkbenchMessages.Question,
                 (Image) null, message, MessageDialog.NONE,
                 new String [] { IDialogConstants.YES_LABEL,
                         IDialogConstants.NO_LABEL }, 0);
         // ensure yes is the default

         return dialog.open() == 0;
     }

     /**
      * Restores control settings that were saved in the previous instance of this
      * page.
      * <p>
      * The <code>WizardDataTransferPage</code> implementation of this method does
      * nothing. Subclasses may override this hook method.
      * </p>
      */
     protected void restoreWidgetValues() {
     }

     /**
      * Saves control settings that are to be restored in the next instance of
      * this page.
      * <p>
      * The <code>WizardDataTransferPage</code> implementation of this method does
      * nothing. Subclasses may override this hook method.
      * </p>
      */
     protected void saveWidgetValues() {
     }

     /**
      * Determine if the page is complete and update the page appropriately.
      */
     protected void updatePageCompletion() {
         boolean pageComplete = determinePageCompletion();
         setPageComplete(pageComplete);
         if (pageComplete) {
             setErrorMessage(null);
         }
     }

     /**
      * Updates the enable state of this page's controls.
      * <p>
      * The <code>WizardDataTransferPage</code> implementation of this method does
      * nothing. Subclasses may extend this hook method.
      * </p>
      */
     protected void updateWidgetEnablements() {
     }

     /**
      * Returns whether this page's destination specification controls currently all
      * contain valid values.
      * <p>
      * The <code>WizardDataTransferPage</code> implementation of this method returns
      * <code>true</code>. Subclasses may reimplement this hook method.
      * </p>
      *
      * @return <code>true</code> indicating validity of all controls in the
      * destination specification group
      */
     protected boolean validateDestinationGroup() {
         return true;
     }

     /**
      * Returns whether this page's options group's controls currently all contain
      * valid values.
      * <p>
      * The <code>WizardDataTransferPage</code> implementation of this method returns
      * <code>true</code>. Subclasses may reimplement this hook method.
      * </p>
      *
      * @return <code>true</code> indicating validity of all controls in the options
      * group
      */
     protected boolean validateOptionsGroup() {
         return true;
     }

     /**
      * Returns whether this page's source specification controls currently all
      * contain valid values.
      * <p>
      * The <code>WizardDataTransferPage</code> implementation of this method returns
      * <code>true</code>. Subclasses may reimplement this hook method.
      * </p>
      *
      * @return <code>true</code> indicating validity of all controls in the
      * source specification group
      */
     protected boolean validateSourceGroup() {
         return true;
     }

     /**
      * Create the options specification widgets.
      *
      * @param parent org.eclipse.swt.widgets.Composite
      */
     protected void createOptionsGroup(Composite parent) {
         // options group
 Group optionsGroup = new Group(parent, SWT.NONE);
         GridLayout layout = new GridLayout();
         optionsGroup.setLayout(layout);
         optionsGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
                 | GridData.GRAB_HORIZONTAL));
         optionsGroup.setText(IDEWorkbenchMessages.WizardExportPage_options);
         optionsGroup.setFont(parent.getFont());

         createOptionsGroupButtons(optionsGroup);

     }

     /**
      * Display an error dialog with the specified message.
      *
      * @param message the error message
      */
     protected void displayErrorDialog(String message) {
         MessageDialog.openError(getContainer().getShell(),
                 getErrorDialogTitle(), message);
     }

     /**
      * Display an error dislog with the information from the
      * supplied exception.
      * @param exception Throwable
      */
     protected void displayErrorDialog(Throwable exception) {
         String message = exception.getMessage();
         //Some system exceptions have no message
 if (message == null) {
             message = NLS.bind(IDEWorkbenchMessages.WizardDataTransfer_exceptionMessage, exception);
         }
         displayErrorDialog(message);
     }

     /**
      * Get the title for an error dialog. Subclasses should
      * override.
      */
     protected String getErrorDialogTitle() {
         return IDEWorkbenchMessages.WizardExportPage_internalErrorTitle;
     }

 }

